package cn.test.server;

import cn.test.utils.DeviceData;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

/***
 *
 *
 * @Author: SJie
 * Date: 2019/12/19 下午5:37
 * Description:
 *
 */


public class ServerMain {
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workGroup = new NioEventLoopGroup();
    int port = 2000;

    public void start() {

        new Thread(new Runnable() {

            public void run() {
                try {
                    ServerBootstrap serverBootstrap = new ServerBootstrap();
                    serverBootstrap.group(bossGroup, workGroup)
                            .handler(new LoggingHandler(LogLevel.INFO))
                            .channel(NioServerSocketChannel.class)
                            // 配置tcp参数
                            // BACKLOG用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，
                            // 用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1，Java将使用默认值50。
                            .option(ChannelOption.SO_BACKLOG, 1024)
                            // 是否启用心跳保活机制。在双方TCP套接字建立连接后（即都进入ESTABLISHED状态）
                            // 并且在两个小时左右上层没有任何数据传输的情况下，这套机制才会被激活。
                            .option(ChannelOption.SO_KEEPALIVE, true)
                            // 在TCP/IP协议中，无论发送多少数据，总是要在数据前面加上协议头，同时，对方接收到数据，也需要发送ACK表示确认。为了尽可能的利用网络带宽，TCP总是希望尽可能的发送足够大的数据。这里就涉及到一个名为Nagle的算法，该算法的目的就是为了尽可能发送大块数据，避免网络中充斥着许多小数据块。
                            //
                            // TCP_NODELAY就是用于启用或关闭Nagle算法。如果要求高实时性，有数据发送时就马上发送，
                            // 就将该选项设置为true关闭Nagle算法；如果要减少发送次数减少网络交互，就设置为false等累积一定大小后再发送。默认为false。
                            .option(ChannelOption.TCP_NODELAY, true)
                            // 处理网络I/O事件
                            .childHandler(new ChannelInitializer<SocketChannel>() {

                                @Override
                                protected void initChannel(SocketChannel socketChannel) throws Exception {
                                    socketChannel.pipeline()
                                            .addLast("IdleStateHandler", new IdleStateHandler(0, 0, 5))
                                            // 自定义长度帧解码器
                                            .addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 1, -1, 1))
//                                            // 预编码消息长度的编码器。 长度值预先作为二进制形式。
//                                            .addLast("frameEncoder", new LengthFieldPrepender(1))
//                                            .addLast(new ServerHeartHandler())
//                                            // java 对象传输
//                                            .addLast(new JdkEncoder())
//                                            .addLast(new JdkDecoder())
//                                            // 字符串编解码器
//                                            .addLast("decoder", new StringDecoder(CharsetUtil.UTF_8))
//                                            .addLast("encoder", new StringEncoder(CharsetUtil.UTF_8))
//                                            .addLast(new IdleStateHandler(3, 3, 0, TimeUnit.SECONDS))
//                                            .addLast(new ServerHandlerOut1())
                                            .addLast(new ServerHandler())
                                            .addLast(new DataHandler());
//                                            .addLast(new ServerHandler())
//
//                                            .addLast(new ServerHandler3())
//                                            .addLast(new ServerHandlerOut2())
//                                            .addLast(new ServerHandlerOut3());


                                }
                            });
                    System.out.println("echo 服务器启动ing！");
                    // 绑定端口，同步等待成功
                    System.out.println("服务开启，同步等待新的连接");
                    Channel channelFuture = serverBootstrap.bind(port).sync().channel();
                    channelFuture.closeFuture().sync();
                } catch (InterruptedException e) {
                    System.out.println("channelFuture异步关闭失败");
                } finally {
                    System.out.println("workGroup/bossGroup释放资源");
                    // 优雅退出，释放资源
                    workGroup.shutdownGracefully();
                    bossGroup.shutdownGracefully();
                }
            }
        }).start();
    }
    public void close(){
//        log.warn("关闭订单socket任务处理");
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        if (workGroup != null) {
            workGroup.shutdownGracefully();
        }
        DeviceData.close();

    }

    public static void main(String[] args) {
        new ServerMain().start();
        new Thread(new Runnable() {
            public void run() {
                int n = 0;
                int[] data = new int[1];
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    if (n % 4 == 0) {
                        data[0] = 0x10;
                    } else {
                        data[0] = 0x11;
                    }

                    DeviceData.send(data);
                    n++;
                }


            }
        }).start();
    }
}
